Quarto Test

Report

Introduction and data

REMOVE THE FOLLOWING TEXT

This section includes an introduction to the project motivation, data, and research question. Describe the data and definitions of key variables.

It should also include some exploratory data analysis.

All of the EDA won’t fit in the paper, so focus on the EDA for the response variable and a few other interesting variables and relationships.

Project Motivation

1999 wurde in der Forschung (Collins et al.) ermittelt, dass die ASA-Klassifizierung des körperlichen Zustands, das Alter, Bluttransfusionen während der Operation und die Dauer von Operationen einen Aufschluss darüber geben, ob der Krankenhausaufenthalt des Patienten länger als gewöhnlich ausfallen wird. Des Weiteren gibt es zahlreiche Studien, bspw. die Forschung von Biber et al. (2012), Singler et al. (2013) oder Ogliari et al. (2022) die festgestellt haben, dass es eine Korrelation zwischen dem Alter von Patienten und der Verweildauer in Notaufnahmen gab. Dieser Frage möchten wir gerne nachgehen und versuchen, die Aufenthaltsdauer vorherzusagen

Data

Uns liegen Daten von nicht-kardiochirurgischen Patienten vor, welche sich von August 2016 bis Juni 2017 einer Routine- oder Notoperation am Seoul National University Hospital, Seoul, Korea, unterzogen. Von den 7.051 in Frage kommenden Fällen wurden Fälle mit lokaler Anästhesie (239), unvollständiger Aufzeichnung (279) und Verlust von wesentlichen Datenspuren (145) ausgeschlossen. Schließlich wurden 6.388 Fälle (91 %), die eine Allgemeinanästhesie, Spinalanästhesie und Sedierung/Analgesie erhielten, in den Datensatz aufgenommen. Der Datensatz besteht aus intraoperativen Vitaldaten und perioperativen klinischen Informationen von 6.388 Fällen. Die Vitaldaten umfassen bis zu 12 Wellenform- und 184 numerische Datenspuren, die von mehreren Anästhesiegeräten erfasst wurden, die den Patienten während der Operation eingesetzt wurden. Die Daten wurden nicht vorverarbeitet, da das reale Rauschen in den Vitaldaten für die Entwicklung praktischer Überwachungsalgorithmen sehr wichtig ist. Insgesamt 74 perioperative klinische Informationsparameter und 34 Zeitreihen perioperativer Laborergebnisse werden zur Verfügung gestellt, um die Interpretation der Beziehung zu den intraoperativen Vitalzeichen zu erleichtern.

Research Question

Wir stellen uns die Frage, welche dem Krankenhaus vorliegenden Daten die Aufenthaltsdauer von Patienten beeinflusst. Da der Datensatz des Seoul National University Hospital (Seoul, Korea) eine,Vielzahl von möglichen Variablen enthält werden wir uns vorerst auf den Zusammenhang zwischen dem Alter der Patienten und der Behandlungsdauer beschäftigen.

Code
import pandas as pd
import altair as alt
import numpy as np
import joblib
import seaborn as sns


from sklearn.feature_selection import SelectFromModel

from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.inspection import permutation_importance

from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error

from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LassoCV
from sklearn.linear_model import Lasso

from statsmodels.formula.api import ols

import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
alt.data_transformers.disable_max_rows()
DataTransformerRegistry.enable('default')

Data preparation

Daten importieren

Code
df = pd.read_csv("https://raw.githubusercontent.com/Maarv99/Project-applied-statistics/main/data/raw/clinical_data.csv")

Wir berechnen eine weitere Variable “op_duartion”. Sie zeigt die Dauer einer Operation an. Dafür subtrahieren wir von der Variablen “opend” die Variable “opstart”.

Code
df['op_duration']=df['opend']-df['opstart']

Wir benennen einige Variablen um: “caseend” bezeichnet das Ende eines Falls, vom Startpunkt 0, daher bennen wir diese Variable “record_duration” Die Variable “icu_days” bezeichnet die Aufenthaltsdauer im Krankenhaus (icu), daher bennen wir diese Variable “length_of_stay” Da wir uns unter der Variable “intraop_ebl” wenig vorstellen konnten, benennen wir diese in “estimated_blood_loss” um.

Code
df=df.rename(columns={'caseend':'recording_duration','icu_days':'length_of_stay','intraop_ebl':'estimated_blood_loss'})

Wir ändern nun den Datentyp der Variable “estimated_blood_loss”, sodass diese korrekt erkannt wird.

Code
df['estimated_blood_loss'] = df['estimated_blood_loss'].fillna(0).astype(int)

Die Spalte ‘age’ enthält u.a. die Zeichen “>89” und “0.7”. Daher wird das Größer-als-Zeichen entfernt und die Werte gerundet, damit es zu int umwandelt werden kann.

Code
df['age'] = df['age'].str.replace('>89', '89').astype(float).round().astype(int)

Wir prüfen unsere Daten auf Zellen ohne Werte

Code
print("Missing values in 'estimated_blood_loss':",df['estimated_blood_loss'].isnull().sum())
print("Missing values in 'op_duration':",df['op_duration'].isnull().sum())
print("Missing values in 'length_of_stay':",df['length_of_stay'].isnull().sum())
print("Missing values in 'bmi':",df['bmi'].isnull().sum())
print("Missing values in 'asa':",df['asa'].isnull().sum())
print("Missing values in 'age':",df['age'].isnull().sum())
print("Missing values in 'recording_duration':",df['recording_duration'].isnull().sum())
print("Missing values in 'sex':",df['sex'].isnull().sum())
Missing values in 'estimated_blood_loss': 0
Missing values in 'op_duration': 0
Missing values in 'length_of_stay': 0
Missing values in 'bmi': 0
Missing values in 'asa': 133
Missing values in 'age': 0
Missing values in 'recording_duration': 0
Missing values in 'sex': 0

Lediglich die Spalte ‘asa’ hat 133 NAs. Diese werden durch den Median der Spalte ersetzt.

Code
df['asa'] = df['asa'].fillna(df['asa'].median())

Wir prüfen, ob der Vorgang korrekt durchgeführt wurde.

Code
df['asa'].isnull().sum()
0

Methodology

REMOVE THE FOLLOWING TEXT

This section includes a brief description of your modeling process.

Explain the reasoning for the type of model you’re fitting, predictor variables considered for the model.

Additionally, show how you arrived at the final model by describing the model selection process, variable transformations (if needed), assessment of conditions and diagnostics, and any other relevant considerations that were part of the model fitting process.

Aufgrund unserer Projektmotivation heraus nutzen wir die dort erwähnten Variablen. Zusätzlich nehmen wir noch die Variable “bmi” hinzu. Diese wird zwar nicht erwähnt, zeigt jedoch auf eine andere Art als die ASA-Klassifizierung (Variable “asa”) auch den Körperlichen Zustand eines Patienten. Aus der Projektmotivation ist auch zu entnehmen, dass wir die Krankenhausaufenhaltsdauer anhand dieser Prädiktoren bestimmen möchten.

Variablen

Code
#Hier kann man auch ggf. emop und department wieder heraus nehmen
df=df[['recording_duration','age','asa','bmi','length_of_stay','op_duration','estimated_blood_loss','emop','department']]

y_label = 'length_of_stay'

features = ['recording_duration',
            'age',
            'asa',
            'bmi',
            'op_duration',
            'estimated_blood_loss']

X = df[features]
y = df[y_label]
Code
#Das kann man ggf. raus löschen, nur falls man sich die unterschiedlichen Abteilungen anschauen möchte, muss man dann aber auch mind. noch bei der Punktewolke mit aufnehmen
alt.Chart(df).mark_bar().encode(
    alt.X(alt.repeat("column"), type="nominal", bin=True),
    y='count()',
).properties(
    width=150,
    height=150
).repeat(
    column=['department']
)
Code
#Das kann man auch ggf. raus löschen nur falls man sich die Notoperationen anschauen möchte, muss man dann aber auch mind. noch bei der Punktewolke mit aufnehmen
hist = alt.Chart(df).mark_bar().encode(
    x=alt.X("emop", 
            bin=alt.BinParams(maxbins=2), 
            scale=alt.Scale(zero=True)),
    y='count()',
)
hist

Wir möchten uns nun die Daten einmal einzeln anschauen

Code
alt.Chart(df).mark_bar().encode(
    alt.X(alt.repeat("column"), type="quantitative", bin=True),
    y='count()',
).properties(
    width=150,
    height=150
).repeat(
    column=['length_of_stay','age','asa','bmi','op_duration','estimated_blood_loss']
)

Boxplots hinzufügen

Nun Betrachten wir die Korrelation der Variablen:

Code
df[['length_of_stay','age','asa','bmi','op_duration','estimated_blood_loss']].corr()
corr = df.corr()
corr[y_label].sort_values(ascending=False)
corr.style.background_gradient(cmap='Blues')
  recording_duration age asa bmi length_of_stay op_duration estimated_blood_loss emop
recording_duration 1.000000 0.058341 0.127565 -0.088701 0.170834 0.989802 0.305259 -0.019633
age 0.058341 1.000000 0.210991 0.067284 -0.011929 0.052445 0.019411 -0.046836
asa 0.127565 0.210991 1.000000 -0.069698 0.214713 0.118595 0.141353 0.179730
bmi -0.088701 0.067284 -0.069698 1.000000 -0.063826 -0.087353 -0.056083 -0.097437
length_of_stay 0.170834 -0.011929 0.214713 -0.063826 1.000000 0.170498 0.185598 0.183334
op_duration 0.989802 0.052445 0.118595 -0.087353 0.170498 1.000000 0.313916 -0.013140
estimated_blood_loss 0.305259 0.019411 0.141353 -0.056083 0.185598 0.313916 1.000000 0.083457
emop -0.019633 -0.046836 0.179730 -0.097437 0.183334 -0.013140 0.083457 1.000000

Wir können eine starke Interkorrelation zwischen op-duration und recording_duration erkennen. Die Korrelation der Prädiktoren mit der Variablen “length_of_stay” ist sehr gering. Wir schauen uns dies nochmal mit Hilfe einer Punktewolke an:

Code
alt.Chart(df).mark_circle().encode(
    alt.X(alt.repeat("column"), type='quantitative'),
    alt.Y(alt.repeat("row"), type='quantitative')
).properties(
    width=150,
    height=150
).repeat(
    row=['length_of_stay'],
    column=['age','asa','bmi','op_duration','estimated_blood_loss']
).interactive()

Nun teilen wir den Datensatz in einen Trainings- und einen Testdatensatz auf

Code
X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size=0.3,
                                                    random_state=42)

Lineare Regression

Wir beginnen nun ein Regressionsmodell aufzustellen

Code
reg = LinearRegression()

Nun erstellen wir die Kreuzvalidierung der Daten mit 5 Folds

Code
scores = cross_val_score(reg, X_train, y_train, cv=5, scoring='neg_mean_squared_error') *-1
# store cross-validation scores
df_scores = pd.DataFrame({"lr": scores})

# reset index to match the number of folds
df_scores.index += 1

alt.Chart(df_scores.reset_index()).mark_line(
     point=alt.OverlayMarkDef()
).encode(
    x=alt.X("index", bin=False, title="Fold", axis=alt.Axis(tickCount=5)),
    y=alt.Y("lr", aggregate="mean", title="Mean squared error (MSE)")
)

Im nächsten Schritt trainieren wir das Modell

Code
reg.fit(X_train, y_train)
LinearRegression()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.

Wir lassen uns nun die Regressionsgerade unsereres Modells berechnen

Code
intercept = pd.DataFrame({
    "Name": ["Intercept"],
    "Coefficient":[reg.intercept_]}
    )

# make a slope table
slope = pd.DataFrame({
    "Name": features,
    "Coefficient": reg.coef_}
)

# combine estimates of intercept and slopes
table = pd.concat([intercept, slope], ignore_index=True, sort=False)

round(table, 3)
Name Coefficient
0 Intercept -0.549
1 recording_duration 0.000
2 age -0.011
3 asa 0.952
4 bmi -0.028
5 op_duration 0.000
6 estimated_blood_loss 0.001

Nun möchten wir sehen, wie gut unser Modell ist

Code
y_pred = reg.predict(X_test)
print("R²:",r2_score(y_test, y_pred).round(3))
print("Adjusted R²:",(1-(1-r2_score(y_test, y_pred))*((len(X_test)-1)/(len(X_test)-len(X_test.columns)-1))).round(4))
print("RMSE:", mean_squared_error(y_test, y_pred, squared=False).round(3))
print("MSE:",mean_squared_error(y_test, y_pred).round(3))
print("MAE:",mean_absolute_error(y_test, y_pred).round(3))
R²: 0.128
Adjusted R²: 0.1249
RMSE: 2.298
MSE: 5.279
MAE: 0.857

Nun möchten wir prüfen, ob unser Modell mit weniger Variablen besser wird, da beispielsweise eine starke Interkorrelation zwischen op-duarion und recording_duration erkennen. Wir nutzen dafür die Vorwärtseliminierung, daher betrachten wir zuerst wie wichtig welche Variable für unser Modell ist. Wir werden im Anschluss unser Modell der Reihe nach mit den wichtigsten Variablen aufbauen und das “Adjusted R²” berechnen, bis dieses nicht mehr besser wird.

Code
importance = np.abs(reg.coef_)

df_imp = pd.DataFrame({"coeff": importance, 
                       "name": features})
alt.Chart(df_imp).mark_bar().encode(
    x="coeff",
    y=alt.Y("name", sort='-x')
)
Code
y_label2 = 'length_of_stay'

features2 = [#'recording_duration',
            #'age',
            'asa',
            #'bmi',
            #'op_duration',
            #'estimated_blood_loss'
            ]

X2 = df[features2]
y2 = df[y_label2]

X_train2, X_test2, y_train2, y_test2 = train_test_split(X2, y2, 
                                                    test_size=0.3,
                                                    random_state=42)

reg.fit(X_train2, y_train2)
y_pred2 = reg.predict(X_test2)

print("R²:",r2_score(y_test2, y_pred2).round(3))
print("Adjusted R²:",(1-(1-r2_score(y_test2, y_pred2))*((len(X_test2)-1)/(len(X_test2)-len(X_test2.columns)-1))).round(4))
print("RMSE:",mean_squared_error(y_test2, y_pred2, squared=False).round(3))
print("MSE:",mean_squared_error(y_test2, y_pred2).round(3))
print("MAE:",mean_absolute_error(y_test2, y_pred2).round(3))
R²: 0.09
Adjusted R²: 0.09
RMSE: 2.346
MSE: 5.504
MAE: 0.917

Nun fügen wir noch die Variable “bmi” zum Modell hinzu

Code
y_label3 = 'length_of_stay'

features3 = [#'recording_duration',
            #'age',
            'asa',
            'bmi',
            #'op_duration',
            #'estimated_blood_loss'
            ]

X3 = df[features3]
y3 = df[y_label3]

X_train3, X_test3, y_train3, y_test3 = train_test_split(X3, y3, 
                                                    test_size=0.3,
                                                    random_state=42)

reg.fit(X_train3, y_train3)
y_pred3 = reg.predict(X_test3)

print("R²:",r2_score(y_test3, y_pred3).round(3))
print("Adjusted R²:",(1-(1-r2_score(y_test3, y_pred3))*((len(X_test3)-1)/(len(X_test3)-len(X_test3.columns)-1))).round(4))
print("RMSE:",mean_squared_error(y_test3, y_pred3, squared=False).round(3))
print("MSE:",mean_squared_error(y_test3, y_pred3).round(3))
print("MAE:",mean_absolute_error(y_test3, y_pred3).round(3))
R²: 0.094
Adjusted R²: 0.0927
RMSE: 2.342
MSE: 5.485
MAE: 0.903

Da sich unser adjusted R² verbessert hat fügen wir nun noch die Variable “age” zum Modell hinzu

Code
y_label4 = 'length_of_stay'

features4 = [#'recording_duration',
            'age',
            'asa',
            'bmi',
            #'op_duration',
            #'estimated_blood_loss'
            ]

X4 = df[features4]
y4 = df[y_label4]

X_train4, X_test4, y_train4, y_test4 = train_test_split(X4, y4, 
                                                    test_size=0.3,
                                                    random_state=42)

reg.fit(X_train4, y_train4)
y_pred4 = reg.predict(X_test4)

print("R²:",r2_score(y_test4, y_pred4).round(3))
print("Adjusted R²:",(1-(1-r2_score(y_test4, y_pred4))*((len(X_test4)-1)/(len(X_test4)-len(X_test4.columns)-1))).round(4))
print("RMSE:",mean_squared_error(y_test4, y_pred4, squared=False).round(3))
print("MSE:",mean_squared_error(y_test4, y_pred4).round(3))
print("MAE:",mean_absolute_error(y_test4, y_pred4).round(3))
R²: 0.103
Adjusted R²: 0.1018
RMSE: 2.33
MSE: 5.427
MAE: 0.903

Unser Adjusted R² verbessert sich weiter, sodass wir die Variable “estimated_blood_loss” zum Modell hinzufügen

Code
y_label5 = 'length_of_stay'

features5 = [#'recording_duration',
            'age',
            'asa',
            'bmi',
            #'op_duration',
            'estimated_blood_loss'
            ]

X5 = df[features5]
y5 = df[y_label5]

X_train5, X_test5, y_train5, y_test5 = train_test_split(X5, y5, 
                                                    test_size=0.3,
                                                    random_state=42)

reg.fit(X_train5, y_train5)
y_pred5 = reg.predict(X_test5)

print("R²:",r2_score(y_test5, y_pred5).round(3))
print("Adjusted R²:",(1-(1-r2_score(y_test5, y_pred5))*((len(X_test5)-1)/(len(X_test5)-len(X_test5.columns)-1))).round(4))
print("RMSE:",mean_squared_error(y_test5, y_pred5, squared=False).round(3))
print("MSE:",mean_squared_error(y_test5, y_pred5).round(3))
print("MAE:",mean_absolute_error(y_test5, y_pred5).round(3))
R²: 0.098
Adjusted R²: 0.0966
RMSE: 2.336
MSE: 5.456
MAE: 0.861

Das Adjusted R² wird weiter besser, wir fügen noch die Variable “op_duration” zum Modell hinzu

Code
y_label6 = 'length_of_stay'

features6 = [#'recording_duration',
            'age',
            'asa',
            'bmi',
            'op_duration',
            'estimated_blood_loss'
            ]

X6 = df[features6]
y6 = df[y_label6]

X_train6, X_test6, y_train6, y_test6 = train_test_split(X6, y6, 
                                                    test_size=0.3,
                                                    random_state=42)

reg.fit(X_train6, y_train6)
y_pred6 = reg.predict(X_test6)

print("R²:",r2_score(y_test6, y_pred6).round(3))
print("Adjusted R²:",(1-(1-r2_score(y_test6, y_pred6))*((len(X_test6)-1)/(len(X_test6)-len(X_test6.columns)-1))).round(4))
print("RMSE:",mean_squared_error(y_test6, y_pred6, squared=False).round(3))
print("MSE:",mean_squared_error(y_test6, y_pred6).round(3))
print("MAE:",mean_absolute_error(y_test6, y_pred6).round(3))
R²: 0.127
Adjusted R²: 0.1252
RMSE: 2.298
MSE: 5.28
MAE: 0.858

Es scheint so, als wäre das Modell mit allen Prediktoren, außer der Variable “recording_duration” das mit der höchsten Güte. Um sicher zu gehen, lassen wir dennoch das Modell mit allen Prediktoren noch einmal berechnen.

Code
y_label7 = 'length_of_stay'

features7 = ['recording_duration',
            'age',
            'asa',
            'bmi',
            'op_duration',
            'estimated_blood_loss'
            ]

X7 = df[features7]
y7 = df[y_label7]

X_train7, X_test7, y_train7, y_test7 = train_test_split(X7, y7, 
                                                    test_size=0.3,
                                                    random_state=42)

reg.fit(X_train7, y_train7)
y_pred7 = reg.predict(X_test7)

print("R²:",r2_score(y_test7, y_pred7).round(3))
print("Adjusted R²:",(1-(1-r2_score(y_test7, y_pred7))*((len(X_test7)-1)/(len(X_test7)-len(X_test7.columns)-1))).round(4))
print("RMSE:",mean_squared_error(y_test7, y_pred7, squared=False).round(3))
print("MSE:",mean_squared_error(y_test7, y_pred7).round(3))
print("MAE:",mean_absolute_error(y_test7, y_pred7).round(3))
R²: 0.128
Adjusted R²: 0.1249
RMSE: 2.298
MSE: 5.279
MAE: 0.857

Beim Modell mit allen Prediktoren zeigt sich ein kleineres adjusted R² also beim Modell ohne “recording_duration”, daher ist das Modell ohne “recording_duration” das mit höchster Güte.

Lasso-Regressionsmodell

Code
scaler = StandardScaler().fit(X_train[features]) 

X_train[features] = scaler.transform(X_train[features])
X_test[features] = scaler.transform(X_test[features])
reg = LassoCV(cv=5, random_state=0)
reg.fit(X_train, y_train)
LassoCV(cv=5, random_state=0)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
Code
reg.alpha_
0.001297668765099978
Code
# Fit the model to the complete training data
regla = Lasso(alpha=reg.alpha_)
regla.fit(X_train, y_train)
Lasso(alpha=0.001297668765099978)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
Code
# intercept
intercept = pd.DataFrame({
    "Name": ["Intercept"],
    "Coefficient":[reg.intercept_]}
    )

# make a slope table
slope = pd.DataFrame({
    "Name": features,
    "Coefficient": reg.coef_}
)

# combine estimates of intercept and slopes
table = pd.concat([intercept, slope], ignore_index=True, sort=False)

round(table, 3)
Name Coefficient
0 Intercept 0.576
1 recording_duration 0.084
2 age -0.160
3 asa 0.635
4 bmi -0.099
5 op_duration 0.251
6 estimated_blood_loss 0.535
Code
y_pred = reg.predict(X_test)

print("R²:",r2_score(y_test, y_pred).round(3))
print("Adjusted R²:",(1-(1-r2_score(y_test, y_pred))*((len(X_test)-1)/(len(X_test)-len(X_test.columns)-1))).round(3))
print("RMSE:",mean_squared_error(y_test, y_pred, squared=False).round(3))
print("MSE:",mean_squared_error(y_test, y_pred).round(3)) 
print("MAE:",mean_absolute_error(y_test, y_pred).round(3))
R²: 0.128
Adjusted R²: 0.125
RMSE: 2.298
MSE: 5.279
MAE: 0.856
Code
import statsmodels.api as sm
from statsmodels.formula.api import ols
from statsmodels.stats.outliers_influence import variance_inflation_factor
from statsmodels.tools.tools import add_constant


models = sm.OLS(y_pred, X_test).fit()

print(models.aic)
3317.6733901507314
Code
print(models.summary())
                                 OLS Regression Results                                
=======================================================================================
Dep. Variable:                      y   R-squared (uncentered):                   0.737
Model:                            OLS   Adj. R-squared (uncentered):              0.736
Method:                 Least Squares   F-statistic:                              891.4
Date:                Fri, 13 Jan 2023   Prob (F-statistic):                        0.00
Time:                        18:15:38   Log-Likelihood:                         -1652.8
No. Observations:                1917   AIC:                                      3318.
Df Residuals:                    1911   BIC:                                      3351.
Df Model:                           6                                                  
Covariance Type:            nonrobust                                                  
========================================================================================
                           coef    std err          t      P>|t|      [0.025      0.975]
----------------------------------------------------------------------------------------
recording_duration      -0.0791      0.094     -0.845      0.398      -0.263       0.105
age                     -0.1545      0.013    -11.580      0.000      -0.181      -0.128
asa                      0.5886      0.015     40.582      0.000       0.560       0.617
bmi                     -0.0736      0.013     -5.710      0.000      -0.099      -0.048
op_duration              0.4241      0.094      4.518      0.000       0.240       0.608
estimated_blood_loss     0.5313      0.014     37.438      0.000       0.503       0.559
==============================================================================
Omnibus:                      135.492   Durbin-Watson:                   0.020
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              253.581
Skew:                           0.495   Prob(JB):                     8.62e-56
Kurtosis:                       4.482   Cond. No.                         14.9
==============================================================================

Notes:
[1] R² is computed without centering (uncentered) since the model does not contain a constant.
[2] Standard Errors assume that the covariance matrix of the errors is correctly specified.

Results

REMOVE THE FOLLOWING TEXT

This is where you will output the final model with any relevant model fit statistics.

Describe the key results from the model. The goal is not to interpret every single variable in the model but rather to show that you are proficient in using the model output to address the research questions, using the interpretations to support your conclusions.

Focus on the variables that help you answer the research question and that provide relevant context for the reader.

Ergebnisse der zwei Modelle im Überblick

Code
results = pd.DataFrame({'': ['R²','Adjusted R²','RMSE','MSE','MAE'],
                        'Lineare Regression': [(r2_score(y_test6, y_pred6).round(3)),
                        ((1-(1-r2_score(y_test6, y_pred6))*((len(X_test6)-1)/(len(X_test6)-len(X_test6.columns)-1))).round(4)),
                        (mean_squared_error(y_test6, y_pred6, squared=False).round(3)),
                        (mean_squared_error(y_test6, y_pred6).round(3)),
                        (mean_absolute_error(y_test6, y_pred6).round(3))], 
                        'Lasso-Regressions': [(r2_score(y_test, y_pred).round(3)),
                        ((1-(1-r2_score(y_test, y_pred))*((len(X_test)-1)/(len(X_test)-len(X_test.columns)-1))).round(3)),
                        (mean_squared_error(y_test, y_pred, squared=False).round(3)),
                        (mean_squared_error(y_test, y_pred).round(3)),
                        (mean_absolute_error(y_test, y_pred).round(3))]})

results
Lineare Regression Lasso-Regressions
0 0.1270 0.128
1 Adjusted R² 0.1252 0.125
2 RMSE 2.2980 2.298
3 MSE 5.2800 5.279
4 MAE 0.8580 0.856

Discussion + Conclusion

REMOVE THE FOLLOWING TEXT

In this section you’ll include a summary of what you have learned about your research question along with statistical arguments supporting your conclusions. In addition, discuss the limitations of your analysis and provide suggestions on ways the analysis could be improved. Any potential issues pertaining to the reliability and validity of your data and appropriateness of the statistical analysis should also be discussed here. Lastly, this section will include ideas for future work.

In den Variablen erkennen wir, dass unsere Vorhersagevarible length_of_stay eine sehr große Streuung besitzt. Wir sehen eine Kollinearität zwischen den Variablen op_duration und recording_duration.

Lineares Regressionsmodell:

Den größten Einfluss auf unser Modell hat die Variable der ASA-Klassifikation.

Unser Modell wird nicht besser, wenn wir eine der verwendeten Variablen ausschließen.

Wir sehen ein kleines R² unseres Modells, was eine geringe Güte des Modells bedeutet. Etwa 18% der Variabilität der Aufenthaltsdauer wird durch das Modell erklärt. Des Weiteren zeigt der mean squared error der einzelnen Folds, dass es sich um kein sehr stabiles Modell handelt.

Lasso Regressionsmodell:

Wir sehen ein kleines R² unseres Modells, was eine geringe Güte des Modells bedeutet. Die Güte ist sogar noch etwas unter der des linearem Regressionsmodells. Etwa 11,8% der Variabilität der Aufenthaltsdauer wird durch das Modell erklärt. Anhand des bereinigten R² sehen wir, das lineare Regressionsmodell ist dem Lasso Regressionsmodell gegenüber zu bevorzugen.

Auch der mean squared error, root mean squared error und der mean absolute error fallen höher, und somit schlechter aus als beim linearen Regressionsmodell. Auch dies weißt darauf hin, dass das lineare Regressionsmodell dem lasso Regressionsmodell zu bevorzugen ist.